package com.sdsy.blockchaintrainingback.service;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.RemoteApiVersion;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;

import java.net.ServerSocket;
import java.time.Duration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class DockerPortFinder {

    private static final int MIN_PORT = 30000;
    private static final int MAX_PORT = 50000;

    public static void main(String[] args) {
        int nextAvailablePortForDocker = findNextAvailablePortForDocker();
        DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("tcp://127.0.0.1:2375").withApiVersion(RemoteApiVersion.VERSION_1_40).build();
        DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
                .dockerHost(config.getDockerHost())
                .maxConnections(100)
                .connectionTimeout(Duration.ofSeconds(30))
                .responseTimeout(Duration.ofSeconds(45))
                .build();
        DockerClient dockerClient = DockerClientBuilder.getInstance(config).withDockerHttpClient(dockerHttpClient).build();
        ExposedPort tcpPort = ExposedPort.tcp(6080);
        Ports portBindings = new Ports();
        portBindings.bind(tcpPort, Ports.Binding.bindPort(nextAvailablePortForDocker));
        CreateContainerResponse container = dockerClient.createContainerCmd("imlala/ubuntu-xfce-vnc-novnc:latest")
                .withExposedPorts(tcpPort,ExposedPort.tcp(5900))
                .withPortBindings(portBindings)
                .withEnv("VNC_PASSWD=123456", "GEOMETRY=1920x1080", "DEPTH=24")
                .exec();

        dockerClient.startContainerCmd(container.getId()).exec();
    }

    public static int findNextAvailablePortForDocker() {
        DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("tcp://172.17.1.100:2375").withApiVersion(RemoteApiVersion.VERSION_1_40).build();
        DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
                .dockerHost(config.getDockerHost())
                .maxConnections(100)
                .connectionTimeout(Duration.ofSeconds(30))
                .responseTimeout(Duration.ofSeconds(45))
                .build();
        DockerClient dockerClient = DockerClientBuilder.getInstance(config).withDockerHttpClient(dockerHttpClient).build();
        Set<Integer> usedPorts = new HashSet<>();

        // Get all containers including the stopped ones
        List<Container> containers = dockerClient.listContainersCmd().withShowAll(true).exec();
        for (Container container : containers) {
            for (ContainerPort portBinding : container.getPorts()) {
                if (portBinding.getPublicPort() != null) {
                    usedPorts.add(portBinding.getPublicPort());
                }
            }
        }

        for (int port = MIN_PORT; port <= MAX_PORT; port++) {
            if (!usedPorts.contains(port) && isPortAvailable(port)) {
                return port;
            }
        }

        throw new RuntimeException("Failed to find an available port within the specified range.");
    }

    public static boolean isPortAvailable(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            serverSocket.setReuseAddress(true);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
